#include "bridge.h"
#include <stdarg.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>

bool platform_pulpino(MemIF* mem, std::list<DbgIF*>* p_list, LogIF *log) {
  p_list->push_back(new DbgIF(mem, 0x1A110000, log));

  return true;
}

Bridge::Bridge(Platforms platform, int portNumber, LogIF *log) {
  initBridge(platform, portNumber, NULL, log);
}

Bridge::Bridge(Platforms platform, MemIF *memIF, LogIF *log) {
  initBridge(platform, 1234, memIF, log);
}

void Bridge::initBridge(Platforms platform, int portNumber, MemIF *memIF, LogIF *log) {

  #include <string>
  using namespace std;
#ifdef __CYGWIN__
  fprintf(stderr, "Try to kill the process that occupies the port %d.\n",portNumber);
  pid_t pid;
  string str = "for /f \"tokens=5\" %%1 in ('netstat -aon^|findstr "+to_string(portNumber)+"') do (taskkill /pid %%1 -t -f)";
  ofstream outfile("tmp.bat", ios::trunc); 
  outfile << str; 
  outfile.close();
  printf("Start CMD\n");
  pid = fork();
  if (pid < 0) 
  {
    exit(1);
  } 
  else if (pid == 0) 
  {
    // execl("C:\\WINDOWS\\SYSTEM32\\CMD.EXE", "cmd.exe", "/v:on", "/q", "/c", 
    //       "\"for", "/f", "\"tokens=5\"", "%1", "in", "('netstat",
    //       "-aon^|findstr", "1234')", "do",
    //       "(taskkill", "/pid", "%1", "-t", "-f)\"",
    //       0);
    execl("C:\\WINDOWS\\SYSTEM32\\CMD.EXE", "cmd.exe", "/c", "call tmp.bat", 0);
  }
  if (waitpid(pid, NULL, 0) < 0)
    exit(1);
  printf("End CMD\n");
#elif _linux_
  fprintf(stderr, "Try to kill the process that occupies the port %d.\n",portNumber);
  string str = "pid=`lsof -i:"+to_string(portNumber)+" | awk 'NR>=2{print $2}'`; kill -9 $pid;";
  system(str.c_str());
#endif

  // initialization
  if (log == NULL)
    this->log = this;
  else
    this->log = log;

  mem = new JtagIF();

  platform_pulpino(mem, &dbgifs, this->log);
  cache = new Cache(mem, &dbgifs);

  bp = new BreakPoints(mem, cache);

  rsp = new Rsp(portNumber, mem, this->log, dbgifs, bp);
}

void Bridge::mainLoop()
{
  // main loop
  while (1) {
    rsp->open();
    int i=5;
    while (!rsp->wait_client())
    {
      i--;
      if (i==0)
      {
        fprintf(stderr, "Wait for a timeout, bridge stop. Maybe the port is being occupied");
        exit(0);
      }
      
    }
    rsp->loop();
    rsp->close();
  }
}

Bridge::~Bridge()
{
  // cleanup
  delete rsp;

  for (std::list<DbgIF*>::iterator it = dbgifs.begin(); it != dbgifs.end(); it++) {
    delete (*it);
  }

  delete bp;
  delete cache;
  delete mem;
}

void Bridge::user(char *str, ...)
{
  va_list va;
  va_start(va, str);
  vprintf(str, va);
  va_end(va);
}

void Bridge::debug(char *str, ...)
{
  va_list va;
  va_start(va, str);
  vprintf(str, va);
  va_end(va);
}
